package cicd

import (
	"log"
	"sync"
	"time"
	"fmt"
	"github.com/pkg/errors"
)

//任务处理器
type Worker struct {
	Id int
	Workbench chan Deployment
	Finished chan bool
}

func newWorker(id int) *Worker {
	return &Worker{
		Id: id,
		Workbench: make(chan Deployment), //no cache
		Finished: make(chan bool),
	}
}

func (w *Worker) Start()  {
	go func() {
		for {
			select {
			case job := <-w.Workbench:
					log.Printf("%d worker do this job " , w.Id)
					//DeployDispatch.deleteRecord(job.Name)
					job.Start()
			case finished := <-w.Finished:
				if finished == true {
					log.Printf("%d 结束工作！\n", w.Id)  //默认并不会结束词常驻携程
					return
				}
			}
		}
	}()
}

func (w *Worker) Stop() {
	go func() {
		w.Finished <- true
	}()
}

const (
	DEFAULT_MAX_WORKERS int  = 5
	DEFAULT_JOB_QUEUE_LEN int = 50
)

type jobStatus struct {
	Name string				`json:"name"`
	JoinTimestamp int64			`json:"joinTimestamp"`
}




type Dispatcher struct {
	MaxWorkers int //default 5
	Workers []*Worker
	JobQueue chan Deployment
	JobQueueStatus map[string]jobStatus
	Closed bool
	sync.Mutex 
}

func newDispatcher() *Dispatcher  {
	return &Dispatcher{
		MaxWorkers: DEFAULT_MAX_WORKERS,
		JobQueue: make(chan Deployment,DEFAULT_JOB_QUEUE_LEN),
		JobQueueStatus: make(map[string]jobStatus),
		Closed: false,
	}
}

func (d *Dispatcher) Run()  {
	for i := 0 ; i < d.MaxWorkers ; i++ {
		worker := newWorker(i+1)
		d.Workers = append(d.Workers,worker)
		go worker.Start()
	}
	go d.Dispatch()
}

func (d *Dispatcher) Dispatch()  {
		for _,work := range d.Workers {
			go func(worker *Worker) {
				for {
					w := <- d.JobQueue
					worker.Workbench <- w
					d.deleteRecord(w.Name)
			}
		}(work)
		}

}

func (d *Dispatcher) record (name string)  {
	j := jobStatus{
		Name: name,
		JoinTimestamp: time.Now().Unix(),
	}
	d.JobQueueStatus[name] = j
}

func (d *Dispatcher) AddJob (deployment Deployment) (error) {
	if d.Closed {
		return errors.New("调度器重启中，请稍后...")
	}
	d.JobQueue <- deployment
	d.record(deployment.Name)
	return nil
}

func  RestartWithMaxWorker(maxWorker int)  {
	DeployDispatch.Closed = true
	for {

		if len(DeployDispatch.JobQueue) == 0 {
			for _,w := range DeployDispatch.Workers {
				go func(worker *Worker) {
					worker.Finished <- true
				}(w)	 //关闭旧worker携程，避免出现僵尸携程，导致内存泄露
			}

			DeployDispatch = newDispatcher()
			DeployDispatch.MaxWorkers = maxWorker
			DeployDispatch.Run()

			return
		}
		fmt.Println("restart dispatch...")
		time.Sleep(time.Second * 1)
	}
}


func (d *Dispatcher) deleteRecord (name string)  {
	delete(d.JobQueueStatus,name)
}


//部署任务队列调度
var DeployDispatch *Dispatcher

func init()  {
	DeployDispatch = newDispatcher()
	DeployDispatch.Run()
}

func GetDeployQueues() (deployJobs) {
	var jobs deployJobs
	fmt.Println(DeployDispatch.JobQueueStatus)

	for _,entry := range DeployDispatch.JobQueueStatus {
		jobs = append(jobs,entry)
	}
	return  jobs
}

type deployJobs []jobStatus

func (jobs deployJobs) Len() int {
	return len(jobs)
}

func (jobs deployJobs) Swap(i, j int){
	jobs[i], jobs[j] = jobs[j], jobs[i]
	}

func (jobs deployJobs) Less(i, j int) bool {
	return jobs[i].JoinTimestamp < jobs[j].JoinTimestamp
}





